#include <stdio.h>
#include <stdlib.h>
#include <yaml.h>
#include <limits.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <bsd/string.h>

#include "conf-yaml.h"

/** 节点全名称最大长度。全名称指，以 . 连接各路径的最终名称 */
#define NODE_NAME_MAX 1024


// 全局变量，保存 解析后的 yaml结构根的地址
static ConfNode *yaml_root = NULL;
// 地址备份使用
static ConfNode *yaml_root_backup = NULL;


/**
 * 获得节点，如果没有找到，则创建节点，并加入到指定位置并返回
 * 在全节点查找
 *
 * 参数：    parent 用来作为父节点的节点
 *          name 想要获取的节点名称
 *          final 设置final标记
 * 返回值：  成功则返回  找到的或者创建的node
 *         失败则返回  NULL
 */
ConfNode *ConfNodeGetNodeOrCreate(ConfNode *parent, const char *name, int final)
{
    ConfNode *node = NULL;
    char node_name[NODE_NAME_MAX];
    char *key;
    char *next;

    if (strlcpy(node_name, name, sizeof(node_name)) >= sizeof(node_name)) {
        fprintf(stderr, "Configuration name too long: %s\n", name);
        return NULL;
    }

    key = node_name;

    do {
        if ((next = strchr(key, '.')) != NULL)
            *next++ = '\0';
        if ((node = ConfNodeLookupChild(parent, key)) == NULL) {
            // 没找到，创建，并设置name
            node = ConfNodeNew(); 
            if (unlikely(node == NULL)) {
                fprintf(stderr, "Failed to allocate memory for configuration.\n");
                goto end;
            }
            node->name = strdup(key);
            if (unlikely(node->name == NULL)) {
                ConfNodeFree(node);
                node = NULL;
                fprintf(stderr, "Failed to allocate memory for configuration.\n");
                goto end;
            }
            node->parent = parent;
            node->final = final;
            // 在父节点插入刚申请的节点
            TAILQ_INSERT_TAIL(&parent->head, node, next);
        }
        // 接续准备下一级查找或者创建
        key = next;
        parent = node;
    } while (next != NULL);

end:
    // 最后返回节点
    return node;
}

/**
 * 封装 ConfNodeGetNodeOrCreate， 从 yaml_root 查找节点
 */
static ConfNode *ConfGetNodeOrCreate(const char *name, int final)
{
    return ConfNodeGetNodeOrCreate(yaml_root, name, final);
}

/**
 * 初始化配置系统，给全局变量 yaml_root 申请 ConfNode 节点
 */
void ConfInit(void)
{
    if (yaml_root != NULL) {
        // fprintf(stdout, "already initialized\n");
        return;
    }
    yaml_root = ConfNodeNew();
    if (yaml_root == NULL) {
        fprintf(stderr, "ERROR: Failed to allocate memory for yaml_root configuration node, "
                   "aborting.\n");
    }
    // fprintf(stdout, "configuration module initialized\n");
}

/**
 * 申请一个 ConfNode 节点
 *
 * 返回值 成功 - 返回申请的配置节点 node
 *       失败 - NULL
 */
ConfNode *ConfNodeNew(void)
{
    ConfNode *new;

    new = calloc(1, sizeof(*new));
    if (unlikely(new == NULL)) {
        return NULL;
    }
    TAILQ_INIT(&new->head);

    return new;
}

/**
 * 释放节点，并递归释放所有子节点
 */
void ConfNodeFree(ConfNode *node)
{
    ConfNode *tmp;

    while ((tmp = TAILQ_FIRST(&node->head))) { // 没有了子节点
        // 从兄弟节点上去掉
        TAILQ_REMOVE(&node->head, tmp, next);
        // 释放节点和子节点
        ConfNodeFree(tmp);
    }

    if (node->name != NULL)
        free(node->name);
    if (node->val != NULL)
        free(node->val);
    free(node);
}

/**
 * 根据节点名字返回节点
 * 从 yaml_root 开始查找，输入 节点的全路径
 * 深度查找
 *
 * 返回值  查询到节点，返回此节点。
 *        如果节点没找到，返回NULL
 */
ConfNode *ConfGetNode(const char *name)
{
    ConfNode *node = yaml_root;
    char node_name[NODE_NAME_MAX];
    char *key;
    char *next;

    if (strlcpy(node_name, name, sizeof(node_name)) >= sizeof(node_name)) {
        fprintf(stderr, "Configuration name too long: %s\n", name);
        return NULL;
    }

    key = node_name;
    do {
        if ((next = strchr(key, '.')) != NULL)
            *next++ = '\0';
        // root 节点是没有数据的，所有从孩子节点中查找
        node = ConfNodeLookupChild(node, key);
        key = next;
    } while (next != NULL && node != NULL);

    return node;
}

/**
 * 返回 yaml_root 值
 */
ConfNode *ConfGetRootNode(void)
{
    return yaml_root;
}

/**
 * 设置配置值，
 * 如果节点找到，并且是final则返回失败
 *
 * 返回值    1 - 设置成功
 *          0 - 设置失败
 */
int ConfSet(const char *name, const char *val)
{
    // 找到节点，没有就创建节点
    ConfNode *node = ConfGetNodeOrCreate(name, 0);
    if (node == NULL || node->final) {
        return 0;
    }
    if (node->val != NULL)
        free(node->val);
    node->val = strdup(val);
    if (unlikely(node->val == NULL)) {
        return 0;
    }
    return 1;
}

/**
 * 从字符串解析yaml节点
 * 举例：  aaa.bbb.ccc = hello world
 * 会被设置成  aaa的子节点bbb的子节点ccc的val值 = "hello world"
 *
 * 返回值    1 - value被设置上
 *          0 - value没有被设置
 */
int ConfSetFromString(const char *input, int final)
{
    int retval = 0;
    char *name = strdup(input), *val = NULL;
    if (unlikely(name == NULL)) {
        goto done;
    }
    val = strchr(name, '=');
    if (val == NULL) {
        goto done;
    }
    *val++ = '\0';

    // 处理name的数据，去掉后方的空白字符
    while (isspace((int)name[strlen(name) - 1])) {
        name[strlen(name) - 1] = '\0';
    }

    // 处理val的数据，去掉前方的空白字符
    while (isspace((int)*val)) {
        val++;
    }

    // 添加 节点  根据 final 设置
    if (final) {
        if (!ConfSetFinal(name, val)) {
            goto done;
        }
    }
    else {
        if (!ConfSet(name, val)) {
            goto done;
        }
    }

    retval = 1;
done:
    if (name != NULL) {
        free(name);
    }
    return retval;
}

/**
 * 设置最终值，并设置为最终值，不能被覆盖，final设置为1
 *
 * 返回值     1 - 设置成功
 *           0 - 设置失败
 */
int ConfSetFinal(const char *name, const char *val)
{
    ConfNode *node = ConfGetNodeOrCreate(name, 1);
    if (node == NULL) {
        return 0;
    }
    if (node->val != NULL)
        free(node->val);
    node->val = strdup(val);
    if (unlikely(node->val == NULL)) {
        return 0;
    }
    node->final = 1;
    return 1;
}

/**
 * 根据名字获取节点值，从yaml_root结点开始查询
 * 输入全路径 和 指向val值的指针的地址。
 * 给 *vptr 赋值的是数据原地址，不是副本。
 * 深度查找
 *
 * 返回值  1 - 节点找到   0 - 没找到节点
 */
int ConfGet(const char *name, const char **vptr)
{
    ConfNode *node = ConfGetNode(name);
    if (node == NULL) {
        // fprintf(stdout, "failed to lookup configuration parameter '%s'\n", name);
        return 0;
    }
    else {
        *vptr = node->val;
        return 1;
    }
}

/**
 * 根据 name 查找指定节点 base 的子节点，并把节点值的地址给到 *vptr
 * 只在子节点查找
 *
 * 返回值     1 - 成功
 *           0 - 失败
 */
int ConfGetChildValue(const ConfNode *base, const char *name, const char **vptr)
{
    ConfNode *node = ConfNodeLookupChild(base, name);

    if (node == NULL) {
        // fprintf(stdout, "failed to lookup configuration parameter '%s'\n", name);
        return 0;
    }
    else {
        if (node->val == NULL)
            return 0;
        *vptr = node->val;
        return 1;
    }
}

/**
 * 从base的子节点中获取名字是name的节点，
 * 如果base节点的子节点找不到则从默认的节点dflt的子节点查找name节点
 * 如果两个都找不到，则返回NULL
 *
 * 返回值:     找到，返回name的节点
 *            找不到，返回NULL
 */
ConfNode *ConfGetChildWithDefault(const ConfNode *base, const ConfNode *dflt,
    const char *name)
{
    ConfNode *node = ConfNodeLookupChild(base, name);
    if (node != NULL)
        return node;

    /* Get 'default' value */
    if (dflt) {
        return ConfNodeLookupChild(dflt, name);
    }
    return NULL;
}

int ConfGetChildValueWithDefault(const ConfNode *base, const ConfNode *dflt,
    const char *name, const char **vptr)
{
    int ret = ConfGetChildValue(base, name, vptr);
    /* Get 'default' value */
    if (ret == 0 && dflt) {
        return ConfGetChildValue(dflt, name, vptr);
    }
    return ret;
}

/**
 * 尝试找到 name 节点并把值转换成 integer 类型的值，赋值给 *val
 *
 * 返回值    1 - 名字被找到，并且争取转换成 integer
 *          0 - 失败
 */
int ConfGetInt(const char *name, intmax_t *val)
{
    const char *strval = NULL;
    intmax_t tmpint;
    char *endptr;

    if (ConfGet(name, &strval) == 0)
        return 0;

    if (strval == NULL) {
        fprintf(stderr, "malformed integer value "
                   "for %s: NULL\n",
                name);
        return 0;
    }

    errno = 0;
    tmpint = strtoimax(strval, &endptr, 0);
    if (strval[0] == '\0' || *endptr != '\0') {
        fprintf(stderr, "malformed integer value "
                   "for %s: '%s'\n",
                name, strval);
        return 0;
    }
    if (errno == ERANGE && (tmpint == INTMAX_MAX || tmpint == INTMAX_MIN)) {
        fprintf(stderr, "integer value for %s out "
                   "of range: '%s'\n",
                name, strval);
        return 0;
    }

    *val = tmpint;
    return 1;
}

/**
 * 从给定的节点 base 的子节点中，查找名字为 name 的配置，然后转换成int类型给 *val 赋值
 *
 * 返回值    1 - 名字被找到，并且正确转换成 integer
 *          0 - 失败
 */
int ConfGetChildValueInt(const ConfNode *base, const char *name, intmax_t *val)
{
    const char *strval = NULL;
    intmax_t tmpint;
    char *endptr;

    if (ConfGetChildValue(base, name, &strval) == 0)
        return 0;
    errno = 0;
    tmpint = strtoimax(strval, &endptr, 0);
    if (strval[0] == '\0' || *endptr != '\0') {
        fprintf(stderr, "malformed integer value "
                   "for %s with base %s: '%s'\n",
                name, base->name, strval);
        return 0;
    }
    if (errno == ERANGE && (tmpint == INTMAX_MAX || tmpint == INTMAX_MIN)) {
        fprintf(stderr, "integer value for %s with "
                   " base %s out of range: '%s'\n",
                name, base->name, strval);
        return 0;
    }

    *val = tmpint;
    return 1;

}


/**
 * 给 ConfGetChildValueInt 加了个壳，base 的子节点 找不到就从 dflt 的子节点里找
 *
 * 返回值    1 - 名字被找到，并且正确转换成 integer
 *          0 - 失败
 */
int ConfGetChildValueIntWithDefault(const ConfNode *base, const ConfNode *dflt,
    const char *name, intmax_t *val)
{
    int ret = ConfGetChildValueInt(base, name, val);
    /* Get 'default' value */
    if (ret == 0 && dflt) {
        return ConfGetChildValueInt(dflt, name, val);
    }
    return ret;
}

/**
 * 根据name用boolean类型检索一个配置值
 *
 * 返回值    1 - 名字被找到，并且正确转换成 Bool 类型 1 或者 0
 *          0 - 失败
 */
int ConfGetBool(const char *name, int *val)
{
    const char *strval = NULL;

    *val = 0;
    if (ConfGet(name, &strval) != 1)
        return 0;

    // 判断是否为真
    *val = ConfValIsTrue(strval);

    return 1;
}

/**
 * 根据name在 base 节点的子节点中用boolean类型检索一个配置值，把转换的值赋值给 *val
 *
 * 返回值    1 - 名字被找到，并且正确转换成 Bool 类型 1 或者 0
 *          0 - 失败
 */
int ConfGetChildValueBool(const ConfNode *base, const char *name, int *val)
{
    const char *strval = NULL;

    *val = 0;
    if (ConfGetChildValue(base, name, &strval) == 0)
        return 0;

    *val = ConfValIsTrue(strval);

    return 1;
}

/**
 * ConfGetChildValueBool的一个封装，如果base的子节点没有，从默认节点 dflt中获取
 *
 * 返回值    1 - 名字被找到，并且正确转换成 Bool 类型 1 或者 0
 *          0 - 失败
 */
int ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt,
    const char *name, int *val)
{
    int ret = ConfGetChildValueBool(base, name, val);
    /* Get 'default' value */
    if (ret == 0 && dflt) {
        return ConfGetChildValueBool(dflt, name, val);
    }
    return ret;
}


/**
 * 判断是否为真
 * 判断是否为 1, yes, true or on
 *
 * 返回值     1 - 是真
 *           0 - 不是真
 */
int ConfValIsTrue(const char *val)
{
    const char *trues[] = {"1", "yes", "true", "on"};
    size_t u;

    for (u = 0; u < sizeof(trues) / sizeof(trues[0]); u++) {
        if (strcasecmp(val, trues[u]) == 0) {
            return 1;
        }
    }

    return 0;
}

/**
 * 判断是否为假，为假返回 1 
 * 判断是否为 0, no, false or off
 *
 * 返回值     1 - 是假
 *           0 - 不是假
 */
int ConfValIsFalse(const char *val)
{
    const char *falses[] = {"0", "no", "false", "off"};
    size_t u;

    for (u = 0; u < sizeof(falses) / sizeof(falses[0]); u++) {
        if (strcasecmp(val, falses[u]) == 0) {
            return 1;
        }
    }

    return 0;
}

/**
 * 使用 dobule 检索一个配置的值给 *val
 * 
 * 返回值        1 - 成功
 *              0 - 失败
 */
int ConfGetDouble(const char *name, double *val)
{
    const char *strval = NULL;
    double tmpdo;
    char *endptr;

    if (ConfGet(name, &strval) == 0)
        return 0;

    errno = 0;
    tmpdo = strtod(strval, &endptr);
    if (strval[0] == '\0' || *endptr != '\0')
        return 0;
    if (errno == ERANGE)
        return 0;

    *val = tmpdo;
    return 1;
}

/**
 * 使用 float 检索一个配置的值给 *val
 * 
 * 返回值        1 - 成功
 *              0 - 失败
 */
int ConfGetFloat(const char *name, float *val)
{
    const char *strval = NULL;
    double tmpfl;
    char *endptr;

    if (ConfGet(name, &strval) == 0)
        return 0;

    errno = 0;
    tmpfl = strtof(strval, &endptr);
    if (strval[0] == '\0' || *endptr != '\0')
        return 0;
    if (errno == ERANGE)
        return 0;

    *val = tmpfl;
    return 1;
}

/**
 * 删除一个给定的节点
 */
void ConfNodeRemove(ConfNode *node)
{
    if (node->parent != NULL)
        // 从兄弟节点上去掉 next 
        TAILQ_REMOVE(&node->parent->head, node, next);
    ConfNodeFree(node);
}

/**
 *
 * 根据名字删除节点
 *
 * 返回值  1 - 成功删除  0 - 没有发现节点
 */
int ConfRemove(const char *name)
{
    ConfNode *node;

    node = ConfGetNode(name);
    if (node == NULL)
        return 0;
    else {
        ConfNodeRemove(node);
        return 1;
    }
}

/**
 * 备份 yaml_root 指向的结构的地址 给 yaml_root_backup
 * 没有数据拷贝
 */
void ConfCreateContextBackup(void)
{
    yaml_root_backup = yaml_root;
    yaml_root = NULL;

    return;
}

/**
 * 还原 yaml_root_backup 指向的结构的地址 给 yaml_root，
 * 没有数据拷贝
 */
void ConfRestoreContextBackup(void)
{
    yaml_root = yaml_root_backup;
    yaml_root_backup = NULL;

    return;
}

/**
 * 清理 yaml_root 节点
 */
void ConfDeInit(void)
{
    if (yaml_root != NULL) {
        ConfNodeFree(yaml_root);
        yaml_root = NULL;
    }

    // fprintf(stdout, "configuration module de-initialized\n");
}


/**
 * 打印 key 的名称
 */
static char *ConfPrintNameArray(char **name_arr, int level)
{
    static char name[128*128];
    int i;

    name[0] = '\0';
    for (i = 0; i <= level; i++) {
        strlcat(name, name_arr[i], sizeof(name));
        if (i < level)
            strlcat(name, ".", sizeof(name));
    }

    return name;
}

/**
 * 打印节点下子节点的数据到标准输出
 * 注意：不打印当前节点
 */
void ConfNodeDump(const ConfNode *node, const char *prefix)
{
    ConfNode *child;

    // 递归调用不重复申请这两个变量
    static char *name[128]; // 128个名字的指针数组
    static int level = -1;  // 层级，yaml_root 属于第0层

    level++;
    // 遍历子节点
    TAILQ_FOREACH(child, &node->head, next) {

        // 申请新的name空间
        name[level] = strdup(child->name);
        if (unlikely(name[level] == NULL)) {
            continue;
        }
        if (prefix == NULL) {
            printf("%s = %s\n", ConfPrintNameArray(name, level),
                child->val);
        }
        else {
            printf("%s.%s = %s\n", prefix,
                ConfPrintNameArray(name, level), child->val);
        }
        ConfNodeDump(child, prefix);
        free(name[level]);
    }
    level--;
}

/**
 * 把 yaml_root 打印到标准输出
 */
void ConfDump(void)
{
    ConfNodeDump(yaml_root, NULL);
}

/*
 * 判断给定的节点有没有子节点 
 * 返回   包含节点 返回 true
 *       不包含节点  返回 false
 */
bool ConfNodeHasChildren(const ConfNode *node)
{
    if (TAILQ_EMPTY(&node->head)) {
        return false;
    }
    return true;
}

/*
 * 根据名字 从 子结点中 根据名字查找，不进行递归查找
 * 没找到返回 NULL 
 * 找到返回 ConfNode 节点地址
 * 只在子节点查找
 */
ConfNode *ConfNodeLookupChild(const ConfNode *node, const char *name)
{
    ConfNode *child;

    if (node == NULL || name == NULL) {
        return NULL;
    }

    // 遍历子节点
    TAILQ_FOREACH(child, &node->head, next) {
        if (child->name != NULL && strcmp(child->name, name) == 0)
            return child;
    }

    return NULL;
}

/**
 * 从子节点中，根据名字找到对应的值
 * 只在子节点查找
 *
 * 参数：     node  父节点
 *           name  节点名字，父节点的路径
 *
 * 返回值：   找到节点，则返回值val的地址
 *           没有找到节点，返回 NULL 
 */
const char *ConfNodeLookupChildValue(const ConfNode *node, const char *name)
{
    ConfNode *child;

    child = ConfNodeLookupChild(node, name);
    if (child != NULL)
        return child->val;

    return NULL;
}

/**
 * 在指定的节点下，查找一个key的值
 * 只在子节点查找
 *
 * 返回值     匹配上         返回匹配的 节点
 *           没匹配上       返回NULL
 */
ConfNode *ConfNodeLookupKeyValue(const ConfNode *base, const char *key,
    const char *value)
{
    ConfNode *child;

    TAILQ_FOREACH(child, &base->head, next) {
        if (!strncmp(child->val, key, strlen(child->val))) {
            ConfNode *subchild;
            TAILQ_FOREACH(subchild, &child->head, next) {
                if ((!strcmp(subchild->name, key)) && (!strcmp(subchild->val, value))) {
                    return child;
                }
            }
        }
    }

    return NULL;
}

/**
 * 测试一个配置节点是否有值
 * 只在子节点查找
 *
 * 返回值            1 - 有节点，也有值
 *                  0 - 没找到节点或者节点没值
 */
int ConfNodeChildValueIsTrue(const ConfNode *node, const char *key)
{
    const char *val;

    val = ConfNodeLookupChildValue(node, key);

    return val != NULL ? ConfValIsTrue(val) : 0;
}

/**
 * 加载一个include引入的yaml文件
 * 
 *  \retval str Pointer to the string path + sig_file
 */
char *ConfLoadCompleteIncludePath(const char *file)
{
    const char *defaultpath = NULL;
    char *path = NULL;

    // 相对路径拼写路径
    if (PathIsRelative(file)) {
        // 获取 include-path 配置文件的相对路径
        if (ConfGet("include-path", &defaultpath) == 1) {
            // fprintf(stdout, "Default path: %s\n", defaultpath);
            size_t path_len = sizeof(char) * (strlen(defaultpath) +
                          strlen(file) + 2);
            path = malloc(path_len);
            if (unlikely(path == NULL))
                return NULL;
            strlcpy(path, defaultpath, path_len);
            if (path[strlen(path) - 1] != '/')
                strlcat(path, "/", path_len);
            strlcat(path, file, path_len);
       } else {
            path = strdup(file);
            if (unlikely(path == NULL))
                return NULL;
        }
    } else {
        path = strdup(file);
        if (unlikely(path == NULL))
            return NULL;
    }
    return path;
}

/**
 * 清空节点 node 里的value值，
 * 如果 node 里的子节点是可被覆盖的，则一并删除。
 * node 节点本身并不被删除，node->name 保留，node->val 被删除
 */
void ConfNodePrune(ConfNode *node)
{
    ConfNode *item, *it;

    for (item = TAILQ_FIRST(&node->head); item != NULL; item = it) {    // 遍历所有子节点
        it = TAILQ_NEXT(item, next) ;
        if (!item->final) {          // 不是最终参数（可被覆盖）
            ConfNodePrune(item) ;    // 递归删除子节点下的数据和自己本身
            if (TAILQ_EMPTY(&item->head)) {              // 子节点为空
                TAILQ_REMOVE(&node->head, item, next) ;  // 节点从数据结构上脱离
                if (item->name != NULL)
                    free(item->name) ;  // 释放 name 
                if (item->val != NULL)
                    free(item->val) ;   // 释放 val，可能调用不到，val 在 递归调用 ConfNodePrune是释放了。且 val 指向了 NULL
                free(item);             // 释放节点
            }
        }
    }

    // 1、没有子节点的节点，val在此处被删除
    // 2、递归前的 node 节点（需要被清理的节点），val值在这里清理
    // 3、node->val = NULL 为了防止重复释放 val
    if (node->val != NULL) {
        free(node->val);
        node->val = NULL;
    }
}

/**
 * 判断节点是不是列表
 *
 * 返回值     1 - 是列表
 *           0 - 不是列表
 */
int ConfNodeIsSequence(const ConfNode *node)
{
    return node->is_seq == 0 ? 0 : 1;
}

/**
 * 判断路径是不是绝对路径
 *
 *  返回值    1 - 是绝对路径
 *           0 - 不是绝对路径 --相对路径 
 */
int PathIsAbsolute(const char *path)
{
    if (strlen(path) > 1 && path[0] == '/') {
        return 1;
    }
    return 0;
}

/**
 *  判断路径是不是相对路径
 *
 *  返回值    1 - 是相对路径
 *           0 - 不是相对路径 --绝对路径
 */
int PathIsRelative(const char *path)
{
    return PathIsAbsolute(path) ? 0 : 1;
}

/**
 * 尝试找到 LIST 的所有数据
 *
 * 返回值    >=0 - 找到的数量
 *          -1  - 失败
 */
int ConfGetList(const char *name, const char *(**val)[])
{
    int ret = -1 ;

    // 获取节点
    ConfNode * base = ConfGetNode(name) ;
    if( base == NULL ) {
        return -1 ;
    } 

    char idx_str[8] ;

    // 查看有多少个子节点
    int idx = 0 ;
    snprintf(idx_str, sizeof(idx_str), "%d", idx) ;
    while(ConfNodeLookupChild(base, idx_str)) {
        idx++ ;
        snprintf(idx_str, sizeof(idx_str), "%d", idx) ;
    }
    
    const char *(*tmpval)[] = calloc(1, sizeof(void *) * idx) ;
    const char * vptr ;

    // 获取每个子节点的value
    idx = 0 ;
    snprintf(idx_str, sizeof(idx_str), "%d", idx) ;
    while( ret = ConfGetChildValue( base, idx_str, &vptr ) ) {
        (*tmpval)[idx] = vptr ;
        idx++ ;
        snprintf(idx_str, sizeof(idx_str), "%d", idx) ;
    }
    *val = tmpval ;
    return idx ;    
}

